/**
 * Iniciação Científica - SAE-CNPQ - 2013/2013
 * autor: Agnaldo A Esmael
 * Orientadores: Prof. Dr Ricardo Torres e Dr. Jefersson A Santos
 * 
 */
package classification;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

import javax.media.jai.PlanarImage;

import control.Dados;

import util.PixelAnotado;

/**
 * NESTA CLASSE DEVE SER ACOPLADO O(S) MÓDULO(S) DE CLASSIFICAÇÃO
 * 
 * A janela interativa irá chamar o método "runClassification" desta classe repetidas vezes até o usuário
 * decidir encerrar a classificação.
 * @author agnaldo
 *
 */

public class Transfer {
	// atributos da classe (variaveis globais):
	Dados dadosBackup;
	PlanarImage imagePlanar;
	BufferedImage imageBuffered;
	int counter = 1;
	
	/**
	 * Construtor da Classe
	 * @param d 	objeto para backup dos dados - Eh uma instancia unica no programa (criada na classe Main)
	 */
	public Transfer(Dados d) {
		
		dadosBackup = d;
		imagePlanar = d.getImage();
		imageBuffered = d.getBufferedImage();
	}
	
	/**
	 * Metodo responsavel por funcionar como "interface" entre a GUI e os Módulos de Classificacao.
	 * Serah chamado repedidas vezes pela classe TratadordeEventosPrincipal ateh o usuario julgar que a 
	 * classificacao da imagem estah boa.
	 * 
	 * Atencao: este metodo nao recebe nenhum parametro.
	 * O acesso aa imagem e aas anotacoes do usuario ocorrem por meio do objeto 'dadosBackup'
	 * 
	 * Jah estah configurado para o ArrayList 'conjuntoDeTreinamento' "receber" as anototacoes do usuario,
	 * esse é um array de vetores do tipo int. Cada vetor deste array representa certo pixel da imagem original, sendo
	 * contem 3 campos: 1º eh a coordenada x do pixel, 2º eh a coordenada y e 3º eh a classe associada a este pixel.
	 * 
	 * Lembrando que a coordenada (0,0) corresponde ao canto superior esquerdo da imagem.
	 * 
	 * Vc deve percorrer o ArrayList 'conjuntoDeTreinamento' para pegar os dados anotados pelo usuario.
	 * Deve, ainda, criar 2 novos objetos ArrayList ao fim do seu processo de classificacao: 
	 * 			1-	Em 'resultado' insira as coordenadas dos pixels que foram classificados
	 * 				como Cafeh. NAO insira em 'resultado' nenhuma informacao referente aos pixels que sao
	 * 				nao-Cafeh.
	 * 
	 * 			2- 	Em 'novoConjuntoDeTreinamento' insira as coordenadas dos pixels que o usuario terah que
	 * 				anotar caso deseje refinar o resultado da classificacao.
	 * 
	 * Por convencao, a classe cafe = 0 (zero) e a nao-cafe = 1 (um).
	 * 
	 * Nao altere os nomes dos ArrayList espeficidados acima.
	 * 
	 * ATENCAO: 'resultado' e 'novoConjuntoDeTreinamento' NAO estao inicializados, vc terah que dar
	 * new ArrayList() em cada um deles e inserir APENAS vetores do tipo int de tamanho = 3, sempre 
	 * que runClassification for chamada. Veja exemplo.
	 * 
	 * @return true se a classificacao foi realizada com sucesso.
	 */
	public boolean runClassification() {
		System.out.println("Etapa de classificação ------- rodada "+ counter++);
		
		
		ArrayList<int[]> conjuntoDeTreinamento;    	//conjunto de pixels que foram inicialmente classificados pelo usuario
		ArrayList<int[]> novoConjuntoDeTreinamento; //contem os pixels que vc quer q o usuario determine a classe
		ArrayList<int[]> resultado;  				//contem APENAS os pixels classificados como Cafeh
		
		conjuntoDeTreinamento = obterAnotacaoDoUsuario();
		
 /* ------------------Jefersson,  INSIRA SEU CÓDIGO AQUI -----------------------------------------------*/
		
		
		
		// Exemplo de como acessar os dados anotados pelo usuário
		//Imprimindo os valores de conjuntoDeTreinamento
		for(int[] i: conjuntoDeTreinamento)
			System.out.println("posição x=" +i[0]+ ", y=" +i[1]+ " Classe:" +i[2]);
		
		
		// A Imagem que vc irah usar para Segmentar, Classificar ... estah disponivel em 2 formatos: PlanarImage e BufferedImage
		//   como elas sao variaveis globais vc pode acessa-las de qualquer posicao desta classe simplesmente chamando pelo seu nome;
		//		
				
				
		// Exemplo de como salvar o seu resultado
		resultado = gerarResultadoQualquer();
		novoConjuntoDeTreinamento = gerarResultadoQualquer();
		
		// Lembre-se sempre de usuar os ArrayLists 'resultado' e 'novoConjuntoDeTreinamento' para salvar seus dados!!!!
		

		
		
/* ----------------------------- NAO ALTERE AQUI -------------------------------------------------*/		
		salvarResultadoDaClassificacao( resultado );
		salvarNovoConjuntoDeTreinamento( novoConjuntoDeTreinamento );
		
		if ( resultado != null && novoConjuntoDeTreinamento != null )
			return true;
		else return false;
		
	}//fim do metodo runClassification
	
	
	/**
	 * Metodo para criar um resultado qualquer. Apenas para teste.
	 * Aqui seram criados 2 regioes retangulares
	 * @return		lista com um resultado aleatorio.
	 */
	private ArrayList<int[]> gerarResultadoQualquer() {
		
		ArrayList <int[]> lista = new ArrayList<int[]>();
		Random generator = new Random();	//objeto que gera numeros aleatorios
		
		int x = generator.nextInt(50);		// x serah um inteiro entre 0 e 49
		int y = generator.nextInt(30);		// y serah uma inteiro entre 0 e 29
		
		// regiao 1
		for(int i = x; i < (x+30); i++)
			for(int j = y; j < (y+20); j++){
				int[] ponto = new int[3];	//criando um vetor para armazenar as coordenadas e classe do pixel
				ponto[0] = i;				//salvando coordenada x do pixel
				ponto[1] = j;				//salvando coordenada y do pixel
				lista.add(ponto); 			//inserindo o vetor no ArrayList
			}
		
		//regiao 2
		for(int i = (2*x+100); i < (3*x+100); i++)
			for(int j = (2*y+100); j < (3*y+100); j++){
				int[] ponto = new int[3];
				ponto[0] = i;
				ponto[1] = j;
				lista.add(ponto);
			}
		
		return lista;
	}//fim do metodo gerarResultadoQualquer
	
	/**
	 * Metodo para acessar os dados da anotacao do usuario que foram salvas no objeto dadosBackup.
	 * @return		lista com os dados anotados pelo usuario
	 */

	private ArrayList<int[]> obterAnotacaoDoUsuario() {
		
		ArrayList <int[]> lista = new ArrayList<int[]>();
		
		Iterator<PixelAnotado> it = dadosBackup.getUserAnotation().iterator();
		while( it.hasNext() ) {
			PixelAnotado  pixel = it.next();
			int[] vector = new int[3];
			vector[0] = pixel.getCoordenada().x;     //acessando a coordenada x do pixel i
			vector[1]= pixel.getCoordenada().y;	 //acessando a coordenada y do pixel i
			vector[2] = pixel.getClasse();		 //acessando a classe deste pixel
			
			lista.add(vector);
			//System.out.println("posição x="+ x +", y=" + y 	+" Classe:" + classe);
		}
		
		return lista;
	}//fim do metodo obterAnotacaoDoUsuario
	
	/**
	 * Metodo para salvar no objetos dadosBackup as coordenadas dos pixels que o usuario
	 * terah que anotar caso queira refinar a classificacao obtida.
	 * @param lista 	ArrayList com as coordenas do novo conjunto de treinamento
	 */
	private void salvarNovoConjuntoDeTreinamento( ArrayList<int[]> lista) {
		if (lista == null) {
			System.out.println(" A Função salvarNovoConjuntoDeTreinamento recebou ArrayList NULO - Nao salvou dados");
			return;
		}
		
		ArrayList<PixelAnotado> listaPixels = new ArrayList<PixelAnotado>();
		
		for(int[] i: lista) 
			listaPixels.add(new PixelAnotado(i[0], i[1]));
		
		dadosBackup.setUserAnotation( listaPixels );
	}//fim do metodo salvarNovoConjuntoDeTreinamento 
	
	/**
	 * Salva no objeto dadosBackup o resultado da classificacao.
	 * @param lista		ArraList com as coordenadas dos pixels classificados como cafeh.
	 */
	private void salvarResultadoDaClassificacao(ArrayList<int[]> lista) {
		if (lista == null) {
			System.out.println(" A Função salvarResultado recebou ArrayList NULO  - Nao salvou dados");
			return;
		}
		
		ArrayList<PixelAnotado> listaPixels = new ArrayList<PixelAnotado>();
		
		for(int[] i: lista) 
			listaPixels.add(new PixelAnotado(i[0], i[1]));
				
		dadosBackup.setClassificationResult( listaPixels );
	}//fim do metodo salvarResultadoDaClassificacao

	
}//fim da Classe Transfer
